﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Media.Animation;
using Gmantis.Controls.Extended;

namespace Gmantis.Controls.DataGrid
{
    [TemplatePart(Name = "EndDateTime", Type = typeof(DateTimePicker)), TemplatePart(Name = "StartDateTime", Type = typeof(DateTimePicker))]
    public class DataGridDateTimeFilter : Control, IDataGridFilter, IDataGridFilterUnity, INotifyPropertyChanged
    {
        // Fields
        private Gmantis.Controls.Extended.DatePickerFormat _dateFormat = Gmantis.Controls.Extended.DatePickerFormat.Short;
        private DateTimePickerEditMode _editMode = DateTimePickerEditMode.DateTime;
        internal DateTimePicker _elementEndDateTime;
        internal DateTimePicker _elementStartDateTime;
        private DateTime? _endDate = null;
        private DataGridFilterState _filter;
        private DayOfWeek _firstDayOfWeek;
        internal bool _isLoaded;
        private DateTime? _startDate = null;
        private TimeEditorFormat _timeFormat;
        internal const string EndDateTimeElementName = "EndDateTime";
        public static readonly DependencyProperty FocusBrushProperty = DependencyProperty.Register("FocusBrush", typeof(Brush), typeof(DataGridDateTimeFilter), null);
        public static readonly DependencyProperty InputBackgroundProperty = DependencyProperty.Register("InputBackground", typeof(Brush), typeof(DataGridDateTimeFilter), null);
        public static readonly DependencyProperty InputForegroundProperty = DependencyProperty.Register("InputForeground", typeof(Brush), typeof(DataGridDateTimeFilter), null);
        public static readonly DependencyProperty MouseOverBrushProperty = DependencyProperty.Register("MouseOverBrush", typeof(Brush), typeof(DataGridDateTimeFilter), null);
        public static readonly DependencyProperty PressedBrushProperty = DependencyProperty.Register("PressedBrush", typeof(Brush), typeof(DataGridDateTimeFilter), null);
        public static readonly DependencyProperty SelectedBackgroundProperty = DependencyProperty.Register("SelectedBackground", typeof(Brush), typeof(DataGridDateTimeFilter), null);
        internal const string StartDateTimeElementName = "StartDateTime";

        // Events
        public event EventHandler<PropertyChangedEventArgs<DataGridFilterState>> FilterChanged;

        public event PropertyChangedEventHandler PropertyChanged;

        // Methods
        public DataGridDateTimeFilter()
        {
            base.DefaultStyleKey = typeof(DataGridDateTimeFilter);
        }

        public void Clear()
        {
            if (this._isLoaded)
            {
                this._elementStartDateTime.DateTime = null;
                this._elementEndDateTime.DateTime = null;
                DataGridFilterState state = this._filter;
                DataGridFilterState state2 = (DataGridFilterState)(this._filter = null);
                if (this.FilterChanged != null)
                {
                    PropertyChangedEventArgs<DataGridFilterState> e = new PropertyChangedEventArgs<DataGridFilterState>
                    {
                        OldValue = state,
                        NewValue = state2
                    };
                    this.FilterChanged(this, e);
                }
            }
        }

        public void Create()
        {
            DataGridFilterState state = this._filter;
            DataGridFilterState filter = this.GetFilter();
            this._filter = filter;
            if (this.FilterChanged != null)
            {
                PropertyChangedEventArgs<DataGridFilterState> e = new PropertyChangedEventArgs<DataGridFilterState>
                {
                    OldValue = state,
                    NewValue = filter
                };
                this.FilterChanged(this, e);
            }
        }

        private static DateTime? GetDateFromValue(object filterValue)
        {
            DateTime? nullable = null;
            if (filterValue is DateTime?)
            {
                return (filterValue as DateTime?);
            }
            if (filterValue is TimeSpan?)
            {
                TimeSpan? nullable2 = filterValue as TimeSpan?;
                if (nullable2.HasValue)
                {
                    nullable = new DateTime?(DateTime.Today.Add(nullable2.Value));
                }
            }
            return nullable;
        }

        protected virtual DataGridFilterState GetFilter()
        {
            if (!this._startDate.HasValue && !this._endDate.HasValue)
            {
                return null;
            }
            List<DataGridFilterInfo> list = new List<DataGridFilterInfo>(2);
            if (this._startDate.HasValue)
            {
                DataGridFilterInfo item = new DataGridFilterInfo
                {
                    FilterOperation = DataGridFilterOperation.GreaterThanOrEqual,
                    FilterCombination = DataGridFilterCombination.None,
                    FilterType = DataGridFilterType.DateTime
                };
                if (this.EditMode == DateTimePickerEditMode.Time)
                {
                    item.Value = this._startDate.Value.TimeOfDay;
                }
                else
                {
                    item.Value = this._startDate.Value;
                }
                list.Add(item);
            }
            if (this._endDate.HasValue)
            {
                DataGridFilterInfo info2 = new DataGridFilterInfo
                {
                    FilterOperation = DataGridFilterOperation.LessThanOrEqual,
                    FilterCombination = this._startDate.HasValue ? DataGridFilterCombination.And : DataGridFilterCombination.None,
                    FilterType = DataGridFilterType.DateTime
                };
                if (this.EditMode == DateTimePickerEditMode.Time)
                {
                    info2.FilterType = DataGridFilterType.Other;
                }
                else
                {
                    info2.Value = this._endDate.Value;
                }
                list.Add(info2);
            }
            return new DataGridFilterState { FilterInfo = list };
        }

        private T GetTemplateChild<T>(string childName, bool required, ref string errors) where T : class
        {
            DependencyObject templateChild = base.GetTemplateChild(childName);
            ApplyTemplateHelper.VerifyTemplateChild(typeof(T), "template part", childName, templateChild, required, ref errors);
            return (templateChild as T);
        }

        private static Storyboard GetTemplateChildResource(FrameworkElement root, string resourceName, bool required, ref string errors)
        {
            return GetTemplateChildResource<Storyboard>(root, resourceName, required, ref errors);
        }

        private static T GetTemplateChildResource<T>(FrameworkElement root, string resourceName, bool required, ref string errors) where T : class
        {
            object child = root.Resources[resourceName];
            ApplyTemplateHelper.VerifyTemplateChild(typeof(T), "resource", resourceName, child, required, ref errors);
            return (child as T);
        }

        public void Load(DataGridFilterState filterState)
        {
            this.SetFilter(filterState);
        }

        private void OnAfterApplyTemplate()
        {
            this._firstDayOfWeek = TimeEditor.GetCurrentDateTimeFormat(this).FirstDayOfWeek;
            Binding binding = new Binding
            {
                Mode = BindingMode.TwoWay
            };
            this._elementStartDateTime.SetBinding(DateTimePicker.DateTimeProperty, binding.From<DataGridDateTimeFilter>(this, x => x.StartDate));
            this._elementStartDateTime.SetBinding(DateTimePicker.DateFormatProperty, new Binding().From<DataGridDateTimeFilter>(this, x => x.DateFormat));
            this._elementStartDateTime.SetBinding(DateTimePicker.TimeFormatProperty, new Binding().From<DataGridDateTimeFilter>(this, x => x.TimeFormat));
            this._elementStartDateTime.SetBinding(DateTimePicker.FirstDayOfWeekProperty, new Binding().From<DataGridDateTimeFilter>(this, x => x.FirstDayOfWeek));
            this._elementStartDateTime.SetBinding(DateTimePicker.EditModeProperty, new Binding().From<DataGridDateTimeFilter>(this, x => x.EditMode));
            Binding binding2 = new Binding
            {
                Mode = BindingMode.TwoWay
            };
            this._elementEndDateTime.SetBinding(DateTimePicker.DateTimeProperty, binding2.From<DataGridDateTimeFilter>(this, x => x.EndDate));
            this._elementEndDateTime.SetBinding(DateTimePicker.DateFormatProperty, new Binding().From<DataGridDateTimeFilter>(this, x => x.DateFormat));
            this._elementEndDateTime.SetBinding(DateTimePicker.TimeFormatProperty, new Binding().From<DataGridDateTimeFilter>(this, x => x.TimeFormat));
            this._elementEndDateTime.SetBinding(DateTimePicker.FirstDayOfWeekProperty, new Binding().From<DataGridDateTimeFilter>(this, x => x.FirstDayOfWeek));
            this._elementEndDateTime.SetBinding(DateTimePicker.EditModeProperty, new Binding().From<DataGridDateTimeFilter>(this, x => x.EditMode));
        }

        public override void OnApplyTemplate()
        {
            string errors = string.Empty;
            base.OnApplyTemplate();
            this._isLoaded = true;
            this._elementStartDateTime = this.GetTemplateChild<DateTimePicker>("StartDateTime", true, ref errors);
            this._elementEndDateTime = this.GetTemplateChild<DateTimePicker>("EndDateTime", true, ref errors);
            if (!string.IsNullOrEmpty(errors))
            {
                this._isLoaded = false;
                if ((base.Template != null) && !PlatformIndependent.IsInDesignMode(this))
                {
                    throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Template cannot be applied to DataGridDateTimeFilter.\nDetails: {0}", new object[] { errors }));
                }
            }
            else
            {
                this.OnAfterApplyTemplate();
            }
        }

        protected void RaisePropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        protected virtual void SetFilter(DataGridFilterState filterState)
        {
            this._startDate = null;
            this._endDate = null;
            this._filter = null;
            if (((filterState != null) && (filterState.FilterInfo != null)) && ((filterState.FilterInfo.Count > 0) && (filterState.FilterInfo[0].FilterType == DataGridFilterType.DateTime)))
            {
                DateTime? dateFromValue = GetDateFromValue(filterState.FilterInfo[0].Value);
                if (filterState.FilterInfo[0].FilterOperation == DataGridFilterOperation.LessThanOrEqual)
                {
                    this._endDate = dateFromValue;
                }
                else if (filterState.FilterInfo[0].FilterOperation == DataGridFilterOperation.GreaterThanOrEqual)
                {
                    this._startDate = dateFromValue;
                }
                if ((filterState.FilterInfo.Count > 1) && (filterState.FilterInfo[1].FilterType == DataGridFilterType.DateTime))
                {
                    dateFromValue = GetDateFromValue(filterState.FilterInfo[1].Value);
                    if (filterState.FilterInfo[1].FilterOperation == DataGridFilterOperation.LessThanOrEqual)
                    {
                        this._endDate = dateFromValue;
                    }
                    else if (filterState.FilterInfo[1].FilterOperation == DataGridFilterOperation.GreaterThanOrEqual)
                    {
                        this._startDate = dateFromValue;
                    }
                }
            }
            this._filter = this.GetFilter();
            this.RaisePropertyChanged("StartDate");
            this.RaisePropertyChanged("EndDate");
            this.RaisePropertyChanged("Filter");
        }

        // Properties
        public Gmantis.Controls.Extended.DatePickerFormat DateFormat
        {
            get
            {
                return this._dateFormat;
            }
            set
            {
                this._dateFormat = value;
                this.RaisePropertyChanged("DateFormat");
            }
        }

        public DateTimePickerEditMode EditMode
        {
            get
            {
                return this._editMode;
            }
            set
            {
                this._editMode = value;
                this.RaisePropertyChanged("EditMode");
            }
        }

        public DateTime? EndDate
        {
            get
            {
                return this._endDate;
            }
            set
            {
                this._endDate = value;
                this._filter = this.GetFilter();
                this.RaisePropertyChanged("EndDate");
                this.RaisePropertyChanged("Filter");
            }
        }

        public DataGridFilterState Filter
        {
            get
            {
                return this._filter;
            }
            set
            {
                this._filter = value;
                this.SetFilter(this._filter);
                this.RaisePropertyChanged("Filter");
            }
        }

        public DayOfWeek FirstDayOfWeek
        {
            get
            {
                return this._firstDayOfWeek;
            }
            set
            {
                this._firstDayOfWeek = value;
                this.RaisePropertyChanged("FirstDayOfWeek");
            }
        }

        public Brush FocusBrush
        {
            get
            {
                return (Brush)base.GetValue(FocusBrushProperty);
            }
            set
            {
                base.SetValue(FocusBrushProperty, value);
            }
        }

        public Brush InputBackground
        {
            get
            {
                return (Brush)base.GetValue(InputBackgroundProperty);
            }
            set
            {
                base.SetValue(InputBackgroundProperty, value);
            }
        }

        public Brush InputForeground
        {
            get
            {
                return (Brush)base.GetValue(InputForegroundProperty);
            }
            set
            {
                base.SetValue(InputForegroundProperty, value);
            }
        }

        public Brush MouseOverBrush
        {
            get
            {
                return (Brush)base.GetValue(MouseOverBrushProperty);
            }
            set
            {
                base.SetValue(MouseOverBrushProperty, value);
            }
        }

        public Brush PressedBrush
        {
            get
            {
                return (Brush)base.GetValue(PressedBrushProperty);
            }
            set
            {
                base.SetValue(PressedBrushProperty, value);
            }
        }

        public Brush SelectedBackground
        {
            get
            {
                return (Brush)base.GetValue(SelectedBackgroundProperty);
            }
            set
            {
                base.SetValue(SelectedBackgroundProperty, value);
            }
        }

        public DateTime? StartDate
        {
            get
            {
                return this._startDate;
            }
            set
            {
                this._startDate = value;
                this._filter = this.GetFilter();
                this.RaisePropertyChanged("EndDate");
                this.RaisePropertyChanged("Filter");
            }
        }

        public TimeEditorFormat TimeFormat
        {
            get
            {
                return this._timeFormat;
            }
            set
            {
                this._timeFormat = value;
                this.RaisePropertyChanged("TimeFormat");
            }
        }
    }
}
